package com.ftcs.service.impl;

import com.ftcs.controller.common.request.StartWorkFlowRequest;
import com.ftcs.controller.common.request.TodoTasksRequest;
import com.ftcs.controller.common.service.ActivitiService;
import com.ftcs.entity.LeaveApply;
import com.ftcs.mapper.LeaveApplyMapper;
import com.ftcs.model.LeaveTaskDTO;
import com.ftcs.model.TodoTaskDTO;
import com.ftcs.service.LeaveService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
// @Transactional(propagation = Propagation.REQUIRED, isolation =
// Isolation.DEFAULT, timeout = 5)
@Service
public class LeaveServiceImpl implements LeaveService {
    @Autowired
    LeaveApplyMapper leaveApplyMapper;
    @Autowired
    IdentityService identityService;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    TaskService taskService;
    @Autowired
    private ActivitiService activitiService;

    @Override
    public String startWorkflow(LeaveApply apply, String userid, String proDefName, Map<String, Object> variables) {
        leaveApplyMapper.save(apply);
        // 使用leaveapply表的主键作为businesskey,连接业务数据和流程数据
        String businesskey = String.valueOf(apply.getId());
        log.info("bussinessKey:{}", businesskey);

        StartWorkFlowRequest request = StartWorkFlowRequest.builder().userId(userid).proDefName(proDefName).businesskey(businesskey).variables(variables).build();
        String processInstanceId = activitiService.startWorkFlow(request);

        apply.setProcess_instance_id(processInstanceId);
        leaveApplyMapper.updateByPrimaryKey(apply);
        return processInstanceId;
    }

    @Override
    public LeaveTaskDTO listTodoTasks(TodoTasksRequest request) {
        TodoTaskDTO todoTaskDTO = activitiService.listTodoTasks(request);
        List<LeaveApply> leaveApplyList = processData(todoTaskDTO.getTaskList());
        return LeaveTaskDTO.builder().pageInfo(todoTaskDTO.getPageInfo()).taskList(leaveApplyList).build();
    }


    @Transactional
    @Override
    public void completeReportBack(String taskId, String realstart_time, String realend_time) {
        String businessKey = activitiService.getBusinessKeyByTaskId(taskId);
        LeaveApply leaveApply = leaveApplyMapper.getLeaveApply(Integer.parseInt(businessKey));
        leaveApply.setReality_start_time(realstart_time);
        leaveApply.setReality_end_time(realend_time);
        leaveApplyMapper.updateByPrimaryKey(leaveApply);
        taskService.complete(taskId);
    }

    private List<LeaveApply> processData(List<Task> tasks) {
        List<LeaveApply> results = tasks.stream().map(task -> {
            String businessKey = activitiService.getBusinessKeyByTaskId(task.getId());
            LeaveApply leaveApply = leaveApplyMapper.getLeaveApply(Integer.parseInt(businessKey));
            leaveApply.setTask(task);
            return leaveApply;
        }).collect(Collectors.toList());
        return results;
    }

    @Override
    public LeaveApply getLeaveApply(int id) {
        LeaveApply leave = leaveApplyMapper.getLeaveApply(id);
        return leave;
    }


    @Override
    public void updateComplete(String taskid, LeaveApply leave, String reapply) {

        String businessKey = activitiService.getBusinessKeyByTaskId(taskid);
        LeaveApply leaveApply = leaveApplyMapper.getLeaveApply(Integer.parseInt(businessKey));
        leaveApply.setLeave_type(leave.getLeave_type());
        leaveApply.setStart_time(leave.getStart_time());
        leaveApply.setEnd_time(leave.getEnd_time());
        leaveApply.setReason(leave.getReason());

        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("reapply", reapply);
        if (reapply.equals("true")) {
            leaveApplyMapper.updateByPrimaryKey(leaveApply);
            taskService.complete(taskid, variables);
        } else {
            taskService.complete(taskid, variables);
        }
    }

    @Override
    public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,
                                            List<HistoricActivityInstance> historicActivityInstances) {
        // 用以保存高亮的线flowId
        List<String> highFlows = new ArrayList<>();
        // 对历史流程节点进行遍历
        for (int i = 0; i < historicActivityInstances.size(); i++) {
            // 得到节点定义的详细信息
            ActivityImpl activityImpl = processDefinitionEntity
                    .findActivity(historicActivityInstances.get(i).getActivityId());
            // 用以保存后需开始时间相同的节点
            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();
            if ((i + 1) >= historicActivityInstances.size()) {
                break;
            }
            // 将后面第一个节点放在时间相同节点的集合里
            ActivityImpl sameActivityImpl1 = processDefinitionEntity
                    .findActivity(historicActivityInstances.get(i + 1).getActivityId());
            sameStartTimeNodes.add(sameActivityImpl1);
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
                // 后续第一个节点
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);
                // 后续第二个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);
                // 如果第一个节点和第二个节点开始时间相同保存
                if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
                    ActivityImpl sameActivityImpl2 = processDefinitionEntity
                            .findActivity(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                } else {
                    // 有不相同跳出循环
                    break;
                }
            }
            // 取出节点的所有出去的线
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
            // 对所有的线进行遍历
            for (PvmTransition pvmTransition : pvmTransitions) {
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }
        return highFlows;
    }
}
